home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / comm / amigatcp.2 < prev    next >
Text File  |  1989-03-18  |  52KB  |  2,346 lines

  1. Path: xanth!ukma!tut.cis.ohio-state.edu!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i081:  amigatcp - tcp/ip for the amiga, Part02/06
  5. Message-ID: <12329@swan.ulowell.edu>
  6. Date: 17 Mar 89 23:16:44 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 2335
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: rminnich@super.org (Ronald G. Minnich)
  12. Posting-number: Volume 89, Issue 81
  13. Archive-name: comm/amigatcp.2
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    icmp.c
  23. #    mbuf.c
  24. #    slip.c
  25. #    smtpcli.c
  26. #    tcpout.c
  27. #    tcpuser.c
  28. #    telnet.c
  29. # This archive created: Fri Mar 17 17:57:17 1989
  30. cat << \SHAR_EOF > icmp.c
  31. /* Internet Control Message Protocol */
  32.  
  33. #include "machdep.h"
  34. #include "internet.h"
  35. #include "timer.h"
  36. #include "ip.h"
  37. #include "icmp.h"
  38. #include "mbuf.h"
  39.  
  40. int (*echo_proc)();    /* Handler for Echo Reply messages */
  41.  
  42. struct icmp_errors icmp_errors;
  43. struct icmp_stats icmp_stats;
  44.  
  45. /* Process an incoming ICMP packet */
  46. void
  47. icmp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  48. struct mbuf *bp;    /* Pointer to ICMP message */
  49. char protocol;        /* Should always be ICMP_PTCL */
  50. int32 source;        /* Sender of ICMP message */
  51. int32 dest;        /* Us */
  52. char tos;        /* Type of Service */
  53. int16 length;        /* Length of ICMP message */
  54. char rxbroadcast;
  55. {
  56.  
  57.     struct icmp *icmph;    /* Pointer to ICMP message */
  58.     struct ip_header *iph;    /* Offending datagram header */
  59.     int16 type;        /* Type of ICMP message */
  60.     int16 ip_len;
  61.  
  62.     if(rxbroadcast){
  63.         /* Broadcast ICMP packets are to be IGNORED !! */
  64.         icmp_errors.bdcsts++;
  65.         free_p(bp);
  66.         return;
  67.     }
  68.     if(cksum(NULLHEADER,bp,length) != 0){
  69.         /* Bad ICMP checksum; discard */
  70.         icmp_errors.checksum++;
  71.         free_p(bp);
  72.         return;
  73.     }
  74.     /* If the message is fragmented, copy to a contiguous mbuf */
  75.     if(bp->next != NULLBUF){
  76.         struct mbuf *nbp;
  77.  
  78.         nbp = copy_p(bp,length);
  79.         free_p(bp);
  80.         if(nbp == NULLBUF){
  81.             icmp_errors.nospace++;
  82.             return;
  83.         }
  84.         bp = nbp;
  85.     }
  86.     icmph = (struct icmp *)bp->data;
  87.  
  88.     /* Process the message. Some messages are passed up to the protocol
  89.      * module for handling, others are handled here.
  90.      */
  91.     type = icmph->type & 0xff;
  92.     if(type < ICMP_TYPES)
  93.         icmp_stats.input[type]++;
  94.  
  95.     switch(type){
  96.     case TIME_EXCEED:    /* Time-to-live Exceeded */
  97.     case DEST_UNREACH:    /* Destination Unreachable */
  98.     case QUENCH:        /* Source Quench */
  99.         iph = (struct ip_header *)(icmph + 1);
  100.         ip_len = (iph->v_ihl & 0xf) * sizeof(int32);
  101.  
  102.         switch(iph->protocol){
  103.         case TCP_PTCL:
  104.             tcp_icmp(ntohl(iph->source),ntohl(iph->dest),
  105.                 icmph->type,icmph->code,(char *)iph + ip_len);
  106.             break;
  107.         }
  108.         break;
  109.     case ECHO:        /* Echo Request */
  110.         /* Change type to ECHO_REPLY, recompute checksum,
  111.          * and return datagram.
  112.          */
  113.         icmph->type = ECHO_REPLY;
  114.         icmph->checksum = 0;
  115.         icmph->checksum = cksum(NULLHEADER,bp,length);
  116.         icmp_stats.output[ECHO_REPLY]++;
  117.         ip_send(dest,source,ICMP_PTCL,tos,0,bp,length,0,0);
  118.         return;
  119.     case REDIRECT:        /* Redirect */
  120.     case PARAM_PROB:    /* Parameter Problem */
  121.         break;
  122.        case ECHO_REPLY:        /* Echo Reply */
  123.         if(echo_proc){
  124.             (*echo_proc)(ntohl(iph->source),ntohl(iph->dest),
  125.              icmph->type,icmph->code,(char *)iph + ip_len);
  126.         }
  127.         break;
  128.     case TIMESTAMP:        /* Timestamp */
  129.     case TIME_REPLY:    /* Timestamp Reply */
  130.     case INFO_RQST:        /* Information Request */
  131.     case INFO_REPLY:    /* Information Reply */
  132.         break;
  133.     }
  134.     free_p(bp);
  135. }
  136. /* Return an ICMP response to the sender of a datagram */
  137. icmp_output(bp,type,code,args)
  138. struct mbuf *bp;        /* Pointer to offending IP header + data */
  139. char type,code;            /* Codes to send */
  140. union icmp_args *args;
  141. {
  142.     struct ip_header *iph;    /* Offending IP header */
  143.     int16 ip_len;        /* Length of offending IP header */
  144.  
  145.     struct mbuf *reply;    /* Buffer with ICMP reply */
  146.     struct icmp *icmph;    /* ICMP protocol header */
  147.     struct mbuf *data;    /* Returned portion of offending packet */
  148.     int16 dlen;        /* Length of data portion of offending pkt */
  149.     int16 length;        /* Total length of reply */
  150.     extern int32 ip_addr;    /* Our IP address */
  151.  
  152.     if(type < ICMP_TYPES)
  153.         icmp_stats.output[type]++;
  154.  
  155.     iph = (struct ip_header *)bp->data;
  156.  
  157.     if(iph->protocol == ICMP_PTCL){
  158.         icmp_errors.noloop++;
  159.         return;    /* Never send an ICMP message about another ICMP message */
  160.     }
  161.     /* Compute amount of original datagram to return.
  162.      * We return the original IP header, and up to 8 bytes past that.
  163.      */
  164.     ip_len = (iph->v_ihl & 0xf) * sizeof(int32);
  165.     dlen = ntohs(iph->length);
  166.     if(dlen > ip_len + 8)
  167.         dlen = ip_len + 8;
  168.     length = sizeof(struct icmp) + dlen;
  169.  
  170.     /* Allocate ICMP header and fill in */
  171.     if((reply = alloc_mbuf(sizeof(struct icmp))) == NULLBUF){
  172.         /* No space; don't bother */
  173.         icmp_errors.nospace++;
  174.         return;
  175.     }
  176.     reply->cnt = sizeof(struct icmp);
  177.     icmph = (struct icmp *)reply->data;
  178.     icmph->type = type;
  179.     icmph->code = code;
  180.     if(args != (union icmp_args *)NULL)
  181.         icmph->args.unused = args->unused;    /* copies whole union */
  182.     else
  183.         icmph->args.unused = 0;
  184.  
  185.     /* Link in a copy of the beginning of the original datagram */
  186.     data = copy_p(bp,dlen);
  187.     reply->next = data;    /* Could be NULL if copy fails */
  188.  
  189.     /* Compute ICMP checksum and send */
  190.     icmph->checksum = 0;
  191.     icmph->checksum = cksum(NULLHEADER,reply,length);
  192.  
  193.     ip_send(ip_addr,ntohl(iph->source),ICMP_PTCL,iph->tos,0,reply,length,0,0);
  194. }
  195. #ifdef    TRACE
  196. /* ICMP message types */
  197. char *icmptypes[] = {
  198.     "Echo Reply",
  199.     NULLCHAR,
  200.     NULLCHAR,
  201.     "Unreachable",
  202.     "Source Quench",
  203.     "Redirect",
  204.     NULLCHAR,
  205.     NULLCHAR,
  206.     "Echo Request",
  207.     NULLCHAR,
  208.     NULLCHAR,
  209.     "Time Exceeded",
  210.     "Parameter Problem",
  211.     "Timestamp",
  212.     "Timestamp Reply",
  213.     "Information Request",
  214.     "Information Reply"
  215. };
  216.  
  217. /* ICMP unreachable messages */
  218. char *unreach[] = {
  219.     "Network",
  220.     "Host",
  221.     "Protocol",
  222.     "Port",
  223.     "Fragmentation",
  224.     "Source route"
  225. };
  226. /* ICMP Time exceeded messages */
  227. char *exceed[] = {
  228.     "Time-to-live",
  229.     "Fragment reassembly"
  230. };
  231.  
  232. /* ICMP redirect messages */
  233. char *redirect[] = {
  234.     "Network",
  235.     "Host",
  236.     "TOS & Network",
  237.     "TOS & Host"
  238. };
  239.  
  240. int
  241. doicmpstat(argc,argv)
  242. int argc;
  243. char *argv[];
  244. {
  245.     extern struct icmp_errors icmp_errors;
  246.     extern struct icmp_stats icmp_stats;
  247.     register int i;
  248.  
  249.     printf("chksum err %u no space %u icmp %u bdcsts %u\r\n",
  250.      icmp_errors.checksum,icmp_errors.nospace,icmp_errors.noloop,
  251.      icmp_errors.bdcsts);
  252.     printf("type  rcvd  sent\r\n");
  253.     for(i=0;i<ICMP_TYPES;i++){
  254.         if(icmp_stats.input[i] == 0 && icmp_stats.output[i] == 0)
  255.             continue;
  256.         printf("%-6u%-6u%-6u",i,icmp_stats.input[i],
  257.             icmp_stats.output[i]);
  258.         if(icmptypes[i] != NULLCHAR)
  259.             printf("  %s",icmptypes[i]);
  260.         printf("\r\n");
  261.     }
  262.     return 0;
  263. }
  264. /* Dump an ICMP header */
  265. void
  266. icmp_dump(bp,source,dest,check)
  267. struct mbuf *bp;
  268. int32 source,dest;
  269. int check;        /* If 0, bypass checksum verify */
  270. {
  271.     register struct icmp *icmp;
  272.     char *codemsg;
  273.     struct mbuf *ibp;
  274.     int i;
  275.     char tmpbuf;
  276.  
  277.     if(bp == NULLBUF)
  278.         return;
  279.     /* If packet isn't in a single buffer, make a temporary copy and
  280.      * note the fact so we free it later
  281.      */
  282.     if(bp->next != NULLBUF){
  283.         bp = copy_p(bp,len_mbuf(bp));
  284.         tmpbuf = 1;
  285.     } else
  286.         tmpbuf = 0;
  287.  
  288.     codemsg = NULLCHAR;
  289.     icmp = (struct icmp *)bp->data;
  290.     if(icmp->type <= 16 && icmptypes[icmp->type] != NULLCHAR)
  291.         printf("ICMP: %s",icmptypes[icmp->type]);
  292.     else
  293.         printf("ICMP: type %u",icmp->type);
  294.  
  295.     switch(icmp->type){
  296.     case DEST_UNREACH:
  297.         if(icmp->code <= 5)
  298.             codemsg = unreach[icmp->code];
  299.         break;
  300.     case REDIRECT:
  301.         if(icmp->code <= 3)
  302.             codemsg = redirect[icmp->code];
  303.         break;
  304.     case TIME_EXCEED:
  305.         if(icmp->code <= 1)
  306.             codemsg = exceed[icmp->code];
  307.         break;
  308.     }    
  309.     if(codemsg != NULLCHAR)
  310.         printf(" %s",codemsg);
  311.     else
  312.         printf(" code %u",icmp->code);
  313.  
  314.     /* Special case for parameter problem message */
  315.     if(icmp->type == PARAM_PROB)
  316.         printf(" pointer = 0x%x",icmp->args.pointer);
  317.  
  318.     if(check){
  319.         /* Verify checksum */
  320.         if((i = cksum(NULLHEADER,bp,len_mbuf(bp))) != 0)
  321.             printf(" CHECKSUM ERROR (%u)",i);
  322.     }
  323.     printf("\r\n");
  324.     /* Dump the offending IP header, if any */
  325.     switch(icmp->type){
  326.     case DEST_UNREACH:
  327.     case TIME_EXCEED:
  328.     case PARAM_PROB:
  329.     case QUENCH:
  330.     case REDIRECT:
  331.         printf("Returned ");
  332.         dup_p(&ibp,bp,sizeof(struct icmp),
  333.             len_mbuf(bp) - sizeof(struct icmp));
  334.         ip_dump(ibp);
  335.         free_p(ibp);
  336.     }
  337.     if(tmpbuf)
  338.         free_p(bp);
  339. }
  340. #endif
  341. SHAR_EOF
  342. cat << \SHAR_EOF > mbuf.c
  343. /* Primitive mbuf allocate/free routines */
  344.  
  345. #ifdef TRACE
  346. #include <stdio.h>
  347. #endif
  348.  
  349. #include "machdep.h"
  350. #include "mbuf.h"
  351.  
  352. /* Allocate mbuf with associated buffer of 'size' bytes */
  353. struct mbuf *
  354. alloc_mbuf(size)
  355. register int16 size;
  356. {
  357.     register struct mbuf *bp;
  358.     char *malloc();
  359.  
  360.     if((bp = (struct mbuf *)malloc((unsigned)(size + sizeof(struct mbuf)))) == NULLBUF)
  361.         return NULLBUF;
  362.     bp->next = bp->anext = NULLBUF;
  363.     if(size != 0){
  364.         bp->data = (char *)(bp + 1);
  365.     } else {
  366.         bp->data = NULLCHAR;
  367.     }
  368.     bp->cnt = 0;
  369.     return bp;
  370. }
  371.  
  372. /* Free all resources associated with mbuf
  373.  * Return pointer to next mbuf in packet chain
  374.  */
  375. struct mbuf *
  376. free_mbuf(bp)
  377. register struct mbuf *bp;
  378. {
  379.     register struct mbuf *bp1 = NULLBUF;
  380.  
  381.     if(bp != NULLBUF){
  382.         bp1 = bp->next;
  383.         free((char *)bp);
  384.     }
  385.     return bp1;
  386. }
  387.  
  388. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  389.  * if any
  390.  */
  391. struct mbuf *
  392. free_p(bp)
  393. register struct mbuf *bp;
  394. {
  395.     struct mbuf *abp;
  396.  
  397.     if(bp == NULLBUF)
  398.         return NULLBUF;
  399.     abp = bp->anext;
  400.     while(bp != NULLBUF)
  401.         bp = free_mbuf(bp);
  402.     return abp;
  403. }        
  404. /* Free entire queue of packets (of mbufs) */
  405. free_q(q)
  406. struct mbuf **q;
  407. {
  408.     register struct mbuf *bp;
  409.  
  410.     while((bp = dequeue(q)) != NULLBUF)
  411.         free_p(bp);
  412. }
  413.  
  414. /* Count up the total number of bytes in an mbuf */
  415. int16
  416. len_mbuf(bp)
  417. register struct mbuf *bp;
  418. {
  419.     int cnt;
  420.  
  421.     cnt = 0;
  422.     while(bp != NULLBUF){
  423.         cnt += bp->cnt;
  424.         bp = bp->next;
  425.     }
  426.     return cnt;
  427. }
  428. /* Count up the number of packets in a queue */
  429. int16
  430. len_q(bp)
  431. register struct mbuf *bp;
  432. {
  433.     register int cnt;
  434.  
  435.     for(cnt=0;bp != NULLBUF;cnt++,bp = bp->anext)
  436.         ;
  437.     return cnt;
  438. }
  439. /* Duplicate/enqueue/dequeue operations based on mbufs */
  440.  
  441. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  442.  * This is done without copying data; only the headers are duplicated,
  443.  * but without data segments of their own. The pointers are set up to
  444.  * share the data segments of the original copy. The return pointer is
  445.  * passed back through the first argument, and the return value is the
  446.  * number of bytes actually duplicated.
  447.  */
  448. int16
  449. dup_p(hp,bp,offset,cnt)
  450. struct mbuf **hp;
  451. register struct mbuf *bp;
  452. register int16 offset;
  453. register int16 cnt;
  454. {
  455.     register struct mbuf *cp;
  456.     int16 tot;
  457.  
  458.     if(cnt == 0 || bp == NULLBUF || hp == (struct mbuf **)NULL){
  459.         if(hp != (struct mbuf **)NULL)
  460.             *hp = NULLBUF;
  461.         return 0;
  462.     }
  463.     if((*hp = cp = alloc_mbuf(0)) == NULLBUF){
  464.         return 0;
  465.     }
  466.     /* Skip over leading mbufs that are smaller than the offset */
  467.     while(bp != NULLBUF && bp->cnt <= offset){
  468.         offset -= bp->cnt;
  469.         bp = bp->next;
  470.     }
  471.     if(bp == NULLBUF){
  472.         free_mbuf(cp);
  473.         *hp = NULLBUF;
  474.         return 0;    /* Offset was too big */
  475.     }
  476.     tot = 0;
  477.     for(;;){
  478.         cp->data = bp->data + offset;
  479.         cp->cnt = min(cnt,bp->cnt - offset);
  480.         offset = 0;
  481.         cnt -= cp->cnt;
  482.         tot += cp->cnt;
  483.         bp = bp->next;
  484.         if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
  485.             break;
  486.         cp = cp->next;
  487.     }
  488.     return tot;
  489. }
  490. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  491. struct mbuf *
  492. copy_p(bp,cnt)
  493. register struct mbuf *bp;
  494. register int16 cnt;
  495. {
  496.     register struct mbuf *cp;
  497.     register char *wp;
  498.     register int16 n;
  499.  
  500.     if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
  501.         return NULLBUF;
  502.     wp = cp->data;
  503.     while(cnt != 0 && bp != NULLBUF){
  504.         n = min(cnt,bp->cnt);
  505.         bcopy(bp->data,wp,n);
  506.         wp += n;
  507.         cp->cnt += n;
  508.         cnt -= n;
  509.         bp = bp->next;
  510.     }
  511.     return cp;
  512. }
  513. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  514.  * bytes actually pulled off
  515.  */
  516. int16
  517. pullup(bph,buf,cnt)
  518. struct mbuf **bph;
  519. char *buf;
  520. int16 cnt;
  521. {
  522.     register struct mbuf *bp;
  523.     int16 n,tot;
  524.  
  525.     tot = 0;
  526.     if(bph == (struct mbuf **)NULL)
  527.         return 0;
  528.     while(*bph != NULLBUF && cnt != 0){
  529.         bp = *bph;
  530.         n = min(cnt,bp->cnt);
  531.         if(buf != NULLCHAR){
  532.             bcopy(bp->data,buf,n);
  533.             buf += n;
  534.         }
  535.         tot += n;
  536.         cnt -= n;
  537.         bp->data += n;
  538.         bp->cnt -= n;        
  539.         if(bp->cnt == 0){
  540.             *bph = free_mbuf(bp);
  541.         }
  542.     }
  543.     return tot;
  544. }
  545. /* Append mbuf to end of mbuf chain */
  546. int16
  547. append(bph,bp)
  548. struct mbuf **bph;
  549. struct mbuf *bp;
  550. {
  551.     register struct mbuf *p;
  552.  
  553.     if(bph == (struct mbuf **)NULL || bp == NULLBUF)
  554.         return;
  555.     if(*bph == NULLBUF){
  556.         /* First one on chain */
  557.         *bph = bp;
  558.     } else {
  559.         for(p = *bph ; p->next != NULLBUF ; p = p->next)
  560.             ;
  561.         p->next = bp;
  562.     }
  563. }
  564. /* Append packet to end of packet queue */
  565. void
  566. enqueue(q,bp)
  567. struct mbuf **q;
  568. struct mbuf *bp;
  569. {
  570.     register struct mbuf *p;
  571.     char i_state;
  572.  
  573.     if(q == (struct mbuf **)NULL || bp == NULLBUF)
  574.         return;
  575.     i_state = disable();
  576.     if(*q == NULLBUF){
  577.         /* List is empty, stick at front */
  578.         *q = bp;
  579.     } else {
  580.         for(p = *q ; p->anext != NULLBUF ; p = p->anext)
  581.             ;
  582.         p->anext = bp;
  583.     }
  584.     restore(i_state);
  585. }
  586. /* Unlink a packet from the head of the queue */
  587. struct mbuf *
  588. dequeue(q)
  589. register struct mbuf **q;
  590. {
  591.     register struct mbuf *bp;
  592.     char i_state;
  593.  
  594.     if(q == (struct mbuf **)NULL)
  595.         return NULLBUF;
  596.     i_state = disable();
  597.     if((bp = *q) != NULLBUF){
  598.         *q = bp->anext;
  599.         bp->anext = NULLBUF;
  600.     }
  601.     restore(i_state);
  602.     return bp;
  603. }    
  604.  
  605. /* Copy user data into an mbuf */
  606. struct mbuf *
  607. qdata(data,cnt)
  608. char *data;
  609. int16 cnt;
  610. {
  611.     register struct mbuf *bp;
  612.  
  613.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  614.         return NULLBUF;
  615.     bcopy(data,bp->data,cnt);
  616.     bp->cnt = cnt;
  617.     return bp;
  618. }
  619. /* Copy mbuf data into user buffer */
  620. int16
  621. dqdata(bp,buf,cnt)
  622. struct mbuf *bp;
  623. char *buf;
  624. unsigned cnt;
  625. {
  626.     unsigned n,tot;
  627.     struct mbuf *bp1;
  628.  
  629.     if(buf == NULLCHAR)
  630.         return 0;
  631.     
  632.     tot = 0;
  633.     for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next){
  634.         n = min(bp1->cnt,cnt);
  635.         bcopy(bp1->data,buf,n);
  636.         cnt -= n;
  637.         buf += n;
  638.         tot += n;
  639.     }
  640.     free_p(bp);
  641.     return tot;
  642. }
  643. #ifdef    TRACE
  644. /* Comment this out if your library already has this function */
  645. #define    isprint(c)    ((c) >= ' ' && (c) < 0x7f)        /* Assumes ASCII */
  646.  
  647. /* Dump an mbuf in hex */
  648. void
  649. hexdump(bp)
  650. struct mbuf *bp;
  651. {
  652.     register struct mbuf *tbp;
  653.     int16 n;
  654.     int16 address;
  655.     void fmtline();
  656.  
  657.     if(bp == NULLBUF)
  658.         return;
  659.     tbp = copy_p(bp,len_mbuf(bp));
  660.     address = 0;
  661.     while(tbp->cnt != 0){
  662.         n = min(tbp->cnt,16);
  663.         fmtline(address,tbp->data,n);
  664.         address += n;
  665.         tbp->data += n;
  666.         tbp->cnt -= n;
  667.     }
  668.     free_p(tbp);
  669.     fflush(stdout);
  670. }
  671. /* Dump an mbuf in ascii */
  672. void
  673. asciidump(bp)
  674. struct mbuf *bp;
  675. {
  676.     struct mbuf *tbp;
  677.     char c;
  678.     int16 tot;
  679.  
  680.     if(bp == NULLBUF)
  681.         return;
  682.     tbp = copy_p(bp,len_mbuf(bp));
  683.     tot = 0;
  684.     while(pullup(&tbp,&c,1) == 1){
  685.         if((tot % 64) == 0)
  686.             printf("%04x  ",tot);
  687.         if(isprint(c))
  688.             putchar(c);
  689.         else
  690.             putchar('.');
  691.         tot++;
  692.         if((tot % 64) == 0)
  693.             printf("\r\n");
  694.     }
  695.     if((tot % 64) != 0)
  696.         printf("\r\n");
  697.     free_p(tbp);
  698.     fflush(stdout);
  699. }
  700. /* Print a buffer up to 16 bytes long in formatted hex with ascii
  701.  * translation, e.g.,
  702.  * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
  703.  */
  704. void
  705. fmtline(addr,buf,len)
  706. int16 addr;
  707. char *buf;
  708. int16 len;
  709. {
  710.     char line[80];
  711.     char *aptr,*cptr;
  712.     int16 c;
  713.     void ctohex();
  714.  
  715.     for(cptr = line;cptr < &line[80];cptr++)
  716.         *cptr = ' ';
  717.     ctohex(line,(int16)hibyte(addr));
  718.     ctohex(line+2,(int16)lobyte(addr));
  719.     aptr = &line[6];
  720.     cptr = &line[55];
  721.     while(len-- != 0){
  722.         c = *buf++ & 0xff;
  723.         ctohex(aptr,c);
  724.         aptr += 3;
  725.         c &= 0x7f;
  726.         if(isprint(c)){
  727.             *cptr++ = c;
  728.         } else {
  729.             *cptr++ = '.';
  730.         }
  731.     }
  732.     *cptr++ = '\r';
  733.     *cptr++ = '\n';
  734. #ifdef    AMIGA
  735.     *cptr = '\0';
  736.     printf(line);
  737. #else
  738.     fwrite(line,1,(unsigned)(cptr-line),stdout);
  739. #endif
  740. }
  741. /* Convert byte to two ascii-hex characters */
  742. static
  743. void
  744. ctohex(buf,c)
  745. char *buf;
  746. int16 c;
  747. {
  748.     static char hex[] = "0123456789abcdef";
  749.  
  750.     buf[0] = hex[hinibble(c)];
  751.     buf[1] = hex[lonibble(c)];
  752. }
  753. #endif
  754. SHAR_EOF
  755. cat << \SHAR_EOF > slip.c
  756. /* Send and receive IP datagrams on serial lines. Compatible with SLIP
  757.  * under Berkeley Unix.
  758.  */
  759. #ifdef    TRACE
  760. #include <stdio.h>
  761. #endif
  762. #include "machdep.h"
  763. #ifdef    TRACE
  764. #include "trace.h"
  765. #endif
  766. #include "mbuf.h"
  767. #include "iface.h"
  768. #include "ax25.h"
  769. #include "slip.h"
  770. #ifdef    AMIGA
  771. #include "amiga.h"
  772. #else
  773. #include "pc.h"
  774. #endif
  775.  
  776. int slip_send();
  777. int doslip();
  778. int asy_output();
  779.  
  780. /* Slip level control structure */
  781. struct slip slip[ASY_MAX];
  782. unsigned nasy;
  783.  
  784. /* Send routine for point-to-point slip
  785.  * This is a trivial function since there is no slip link-level header
  786.  */
  787. int
  788. slip_send(bp,interface,gateway,precedence,delay,throughput,reliability)
  789. struct mbuf *bp;        /* Buffer to send */
  790. struct interface *interface;    /* Pointer to interface control block */
  791. int32 gateway;            /* Ignored (SLIP is point-to-point) */
  792. char precedence;
  793. char delay;
  794. char throughput;
  795. char reliability;
  796. {
  797.     /* Queue a frame on the slip output queue and start transmitter */
  798.  
  799.     if(interface == NULLIF){
  800.         free_p(bp);
  801.         return;
  802.     }
  803. #ifdef    TRACE
  804.     if(trace & TRACE_SLIP){
  805.         printf("%s sent:\r\n",interface->name);
  806.         if((trace & TRACE_HDR) > 2)
  807.             ip_dump(bp);
  808.         if(trace & TRACE_DUMP)
  809.             hexdump(bp);
  810.         if(trace & TRACE_ASCII)
  811.             asciidump(bp);
  812.         fflush(stdout);
  813.     }
  814. #endif
  815.     slipq(interface->dev,bp);
  816. }
  817. /* Encode a packet in slip framing, put on link output queue, and kick
  818.  * transmitter
  819.  */
  820. slipq(dev,bp)
  821. int16 dev;        /* Serial line number */
  822. struct mbuf *bp;    /* Buffer to be sent */
  823. {
  824.     register struct slip *sp;
  825.     struct mbuf *slip_encode();
  826.  
  827.     if((bp = slip_encode(bp)) == NULLBUF)
  828.         return;    
  829.  
  830.     sp = &slip[dev];
  831.     enqueue(&sp->sndq,bp);
  832.     sp->sndcnt++;
  833.     if(sp->tbp == NULLBUF)
  834.         asy_start(dev);
  835. }
  836. /* Start output, if possible, on asynch device dev */
  837. static
  838. asy_start(dev)
  839. int16 dev;
  840. {
  841.     register struct slip *sp;
  842.  
  843.     if(!stxrdy(dev))
  844.         return;        /* Transmitter not ready */
  845.  
  846.     sp = &slip[dev];
  847.     if(sp->tbp != NULLBUF){
  848.         /* transmission just completed */
  849.         free_p(sp->tbp);
  850.         sp->tbp = NULLBUF;
  851.     }
  852.     if(sp->sndq == NULLBUF)
  853.         return;    /* No work */
  854.  
  855.     sp->tbp = dequeue(&sp->sndq);
  856.     sp->sndcnt--;
  857.     asy_output(dev,sp->tbp->data,sp->tbp->cnt);
  858. }
  859. /* Encode a packet in SLIP format */
  860. static
  861. struct mbuf *
  862. slip_encode(bp)
  863. struct mbuf *bp;
  864. {
  865.     struct mbuf *lbp;    /* Mbuf containing line-ready packet */
  866.     register char *cp;
  867.     register int cnt;
  868.     char c;
  869.  
  870.     /* Allocate output mbuf that's twice as long as the packet.
  871.      * This is a worst-case guess (consider a packet full of FR_ENDs!)
  872.      */
  873.     lbp = alloc_mbuf(2*len_mbuf(bp) + 2);
  874.     if(lbp == NULLBUF){
  875.         /* No space; drop */
  876.         free_p(bp);
  877.         return NULLBUF;
  878.     }
  879.     cp = lbp->data;
  880.     cnt = 0;
  881.  
  882.     /* Flush out any line garbage */
  883.     *cp++ = FR_END;
  884.     cnt++;
  885.  
  886.     /* Copy input to output, escaping special characters */
  887.     while(pullup(&bp,&c,1) == 1){
  888.         switch(c & 0xff){
  889.         case FR_ESC:
  890.             *cp++ = FR_ESC;
  891.             *cp++ = T_FR_ESC;
  892.             cnt += 2;
  893.             break;
  894.         case FR_END:
  895.             *cp++ = FR_ESC;
  896.             *cp++ = T_FR_END;
  897.             cnt += 2;
  898.             break;
  899.         default:
  900.             *cp++ = c;
  901.             cnt++;
  902.         }
  903.     }
  904.     *cp++ = FR_END;
  905.     cnt++;
  906.     lbp->cnt = cnt;
  907.     return lbp;
  908. }
  909. /* Process incoming bytes in SLIP format
  910.  * When a buffer is complete, return it; otherwise NULLBUF
  911.  */
  912. static
  913. struct mbuf *
  914. slip_decode(dev,c)
  915. int dev;    /* Slip unit number */
  916. char c;        /* Incoming character */
  917. {
  918.     struct mbuf *bp,*nbp;
  919.     register struct slip *sp;
  920.  
  921.     sp = &slip[dev];
  922.     switch(c & 0xff){
  923.     case FR_END:
  924.         if(sp->rbp != NULLBUF){
  925.             /* Kick upstairs */
  926.             bp = sp->rbp;
  927.             sp->rbp = NULLBUF;
  928.             sp->rcnt = 0;
  929.             /* Copy into contiguous buffer, if necessary */
  930.             if(bp->next != NULLBUF){
  931.                 nbp = copy_p(bp,len_mbuf(bp));
  932.                 free_p(bp);
  933.                 bp = nbp;
  934.             }
  935.             return bp;
  936.         }
  937.         return NULLBUF;
  938.     case FR_ESC:
  939.         sp->escaped = 1;
  940.         return NULLBUF;
  941.     }
  942.     if(sp->escaped){
  943.         sp->escaped = 0;
  944.         switch(c & 0xff){
  945.         case T_FR_ESC:
  946.             c = FR_ESC;
  947.             break;
  948.         case T_FR_END:
  949.             c = FR_END;
  950.             break;
  951.         default:
  952.             sp->errors++;
  953.         }
  954.     }
  955.     if(sp->rcnt == SLIP_MTU){
  956.         /* Packet is too large, drop it and start over */
  957.         free_p(sp->rbp);
  958.         sp->rbp = NULLBUF;
  959.         sp->rcnt = 0;
  960.         return NULLBUF;
  961.     }
  962.     /* We reach here with a character for the buffer;
  963.      * make sure there's space for it
  964.      */
  965.     if(sp->rbp == NULLBUF){
  966.         /* Allocate first mbuf for new packet */
  967.         if((sp->rbp1 = sp->rbp = alloc_mbuf(SLIP_ALLOC)) == NULLBUF)
  968.             return NULLBUF; /* No memory, drop */
  969.         sp->rcp = sp->rbp->data;
  970.     } else if(sp->rbp1->cnt == SLIP_ALLOC){
  971.         /* Current mbuf is full; link in another */
  972.         if((sp->rbp1->next = alloc_mbuf(SLIP_ALLOC)) == NULLBUF){
  973.             /* No memory, drop whole thing */
  974.             free_p(sp->rbp);
  975.             sp->rbp = NULLBUF;
  976.             sp->rcnt = 0;
  977.             return NULLBUF;
  978.         }
  979.         sp->rbp1 = sp->rbp1->next;
  980.         sp->rcp = sp->rbp1->data;
  981.     }
  982.     /* Store the character, increment fragment and total
  983.      * byte counts
  984.      */
  985.     *sp->rcp++ = c;
  986.     sp->rbp1->cnt++;
  987.     sp->rcnt++;
  988.     return NULLBUF;
  989. }
  990. /* Process SLIP line I/O */
  991. int
  992. doslip(interface)
  993. struct interface *interface;
  994. {
  995.     char c;
  996.     struct mbuf *bp;
  997.     int16 dev;
  998.  
  999.     dev = interface->dev;
  1000.     /* Process any pending input */
  1001.     while(asy_recv(dev,&c,1) != 0)
  1002.         if((bp = slip_decode(dev,c)) != NULLBUF)
  1003.             (*slip[dev].recv)(interface,bp);
  1004.  
  1005.     /* Kick the transmitter if it's idle */
  1006.     if(stxrdy(dev))
  1007.         asy_start(dev);
  1008. }
  1009. /* Unwrap incoming SLIP packets -- trivial operation since there's no
  1010.  * link level header
  1011.  */
  1012. slip_recv(interface,bp)
  1013. struct interface *interface;
  1014. struct mbuf *bp;
  1015. {
  1016. #ifdef    TRACE
  1017.     if(trace & TRACE_SLIP){
  1018.         printf("%s recv:\r\n",interface->name);
  1019.         if((trace & TRACE_HDR) > 2)
  1020.             ip_dump(bp);
  1021.         if(trace & TRACE_DUMP)
  1022.             hexdump(bp);
  1023.         if(trace & TRACE_ASCII)
  1024.             asciidump(bp);
  1025.         fflush(stdout);
  1026.     }
  1027. #endif
  1028.     ip_route(bp,0);
  1029. /* Attach a serial interface to the system
  1030.  * argv[0]: hardware type, must be "asy"
  1031.  * argv[1]: I/O address, e.g., "0x3f8"
  1032.  * argv[2]: vector, e.g., "4"
  1033.  * argv[3]: mode, may be:
  1034.  *        "slip" (point-to-point SLIP)
  1035.  *        "ax25" (AX.25 UI frame format in SLIP for raw TNC)
  1036.  * argv[4]: interface label, e.g., "sl0"
  1037.  * argv[5]: receiver ring buffer size in bytes
  1038.  * argv[6]: maximum transmission unit, bytes
  1039.  * argv[7]: interface speed, e.g, "9600"
  1040.  */
  1041. asy_attach(argc,argv)
  1042. int argc;
  1043. char *argv[];
  1044. {
  1045.     register struct interface *if_asy;
  1046.     extern struct interface *ifaces;
  1047.     int dev;
  1048.     char *malloc(), *calloc();
  1049.     int asy_init();
  1050.     int asy_send();
  1051.     int doslip();
  1052.     int asy_stop();
  1053.     int ax_send();
  1054.     int kiss_recv();
  1055.     int kiss_output();
  1056.  
  1057.     if(nasy >= ASY_MAX){
  1058.         printf("Too many asynch controllers\r\n");
  1059.         return -1;
  1060.     }
  1061.     dev = nasy++;
  1062.  
  1063.     /* Initialize hardware-level control structure */
  1064.     asy[dev].addr = htoi(argv[1]);
  1065.     asy[dev].vec = htoi(argv[2]);
  1066.  
  1067.     /* Create interface structure and fill in details */
  1068.     if_asy = (struct interface *)calloc(1, sizeof(struct interface));
  1069.  
  1070.     if_asy->name = malloc(strlen(argv[4])+1);
  1071.     strcpy(if_asy->name,argv[4]);
  1072.     if_asy->mtu = atoi(argv[6]);
  1073.     if_asy->dev = dev;
  1074.     if_asy->recv = doslip;
  1075.     if_asy->stop = asy_stop;
  1076.  
  1077.     if(strcmp(argv[3],"slip") == 0){
  1078.         if_asy->send = slip_send;
  1079.         if_asy->output = NULLFP;
  1080.         if_asy->flags = 0;
  1081.         slip[dev].recv = slip_recv;
  1082.     }
  1083.     else if(strcmp(argv[3],"ax25") == 0){
  1084.         if_asy->send = ax_send;
  1085.         if_asy->output = kiss_output;
  1086.         if_asy->flags = IF_BROADCAST;
  1087.         if(if_asy->hwaddr == NULLCHAR)
  1088.             if_asy->hwaddr = malloc(AXALEN);
  1089.         bcopy((char *)&mycall,if_asy->hwaddr,AXALEN);
  1090.         slip[dev].recv = kiss_recv;
  1091.     }
  1092.     else {
  1093.         printf("Mode %s unknown for interface %s\r\n",
  1094.             argv[3],argv[4]);
  1095.         free((char *)if_asy);
  1096.         return -1;
  1097.     }
  1098.     if_asy->next = ifaces;
  1099.     ifaces = if_asy;
  1100.     asy_init(dev,(unsigned)atoi(argv[5]));
  1101.     asy_speed(dev,atoi(argv[7]));
  1102. }
  1103. SHAR_EOF
  1104. cat << \SHAR_EOF > smtpcli.c
  1105. /* smtpcli.c
  1106.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  1107.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  1108.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  1109.  *    Permission granted for non-commercial copying and use, provided
  1110.  *    this notice is retained.
  1111.  */
  1112.  
  1113. #include <stdio.h>
  1114. #include "machdep.h"
  1115. #include "netuser.h"
  1116. #include "mbuf.h"
  1117. #include "timer.h"
  1118. #include "tcp.h"
  1119. #include "smtp.h"
  1120.  
  1121. extern int16 lport;            /* local port placeholder */
  1122. int32 aton();
  1123. static void sendit();
  1124. static struct timer smtpcli_t;
  1125. char *index(),*rindex();
  1126.  
  1127. /* init routine called when program fired up */
  1128. smtpclinit()
  1129. {
  1130.     int dosmtptick();
  1131.  
  1132.     smtpcli_t.func = (void (*)())dosmtptick;/* what to call on timeout */
  1133.     smtpcli_t.arg = 0;            /* dummy value */
  1134.     smtpcli_t.start = SMTPCLITIME;        /* set timer duration */
  1135.     start_timer(&smtpcli_t);        /* and fire it up */
  1136. }
  1137.  
  1138. /* this is the routine that gets called every so often to do outgoing mail
  1139.    processing */
  1140. int
  1141. dosmtptick()
  1142. {
  1143.     char     lfilename[LINELEN],
  1144.         tmpstring[LINELEN],
  1145.         wfilename[13],
  1146.         *ptr;
  1147.     FILE *lfile;
  1148.     struct smtp_msg *mp;
  1149.     struct socket lsocket, fsocket;
  1150.     char *calloc(),*malloc();
  1151.     void smtp_rec(), smtp_cts(), smtp_state();
  1152.  
  1153. /*    printf("DOSMTPTICK() entered\n");    */
  1154.     lsocket.address = ip_addr;    /* our ip address */
  1155.     fsocket.port = SMTP_PORT;
  1156. /* if lock file exists in mqueue dir, return */
  1157.     sprintf(lfilename,"%s%s",MAILQDIR,"lockfile");
  1158.     if ((lfile = fopen(lfilename,"x")) == NULL)
  1159.         return;
  1160. /* get next work filename from mqueue directory */
  1161.     sprintf(tmpstring,"%s%s",MAILQDIR,"*.wrk");
  1162. #ifndef    AMIGA
  1163.     filedir(tmpstring,0,wfilename);
  1164. #endif
  1165.     if (wfilename[0] == '\0')
  1166.         return;    /* no work to be done */
  1167. /* if we have work, rebuild the exact (non-wild) filename */
  1168.     mp = (struct smtp_msg *)calloc(1,sizeof (struct smtp_msg));
  1169.     sprintf(tmpstring,"%s%s",MAILQDIR,wfilename);
  1170.     ptr = &tmpstring[0];
  1171.     mp->filename = malloc((unsigned)strlen(ptr)+1);
  1172.     strcpy(mp->filename,ptr);
  1173. /*    printf("work file name: %s\n",mp->filename);    /* debug only */
  1174.     mp->wfile = fopen(mp->filename,"r");
  1175. /*   get ip address, from stuff, to stuff */
  1176.     fgets(tmpstring,LINELEN,mp->wfile);    /* read target ip addr */
  1177. /*    printf("target ip addr: %s\n",tmpstring);    */
  1178.     fgets(mp->toaddr,LINELEN,mp->wfile);        /* who to */
  1179.     rip(mp->toaddr);
  1180. /*    printf("addressee: %s\n",mp->toaddr);        */
  1181.     fgets(mp->fromaddr,LINELEN,mp->wfile);        /* who from */
  1182.     rip(mp->fromaddr);
  1183. /*    printf("sender: %s\n",mp->fromaddr);        */
  1184.     fclose(mp->wfile);
  1185. /* set up the rest of the socket info from what we got */
  1186.     fsocket.address = aton(tmpstring);    /* destination ip address */
  1187.     lsocket.port = lport++;            /* next unused port */
  1188. /*   open smtp connection */
  1189.     mp->state = CLI_OPEN_STATE;        /* init state placeholder */
  1190. /*    printf("Opening TCP connection for SMTP client\n");    */
  1191.     mp->tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,1024,
  1192.             smtp_rec,smtp_cts,smtp_state,0,(int *)mp);
  1193.     mp->tcb->user = (int *)mp;        /* Upward pointer */
  1194.  
  1195. /*    printf("releasing lock\n");        */
  1196.     if (lfile != NULL) {            /* release lock */
  1197.         fclose(lfile);
  1198.         unlink(lfilename);
  1199.     }
  1200. }
  1201.  
  1202. /* replace terminating end of line marker(s) with null */
  1203. rip(s)
  1204. char *s;
  1205. {
  1206.     char *c;
  1207.  
  1208.     c=s;
  1209.     while (*c != '\0') {
  1210.         switch (*c) {
  1211.         case '\r':
  1212.         case '\n':
  1213.             *c='\0';
  1214.             break;
  1215.         default:
  1216.             c++;
  1217.             break;
  1218.         }
  1219.     }
  1220. }
  1221.  
  1222. /* this is the master state machine that handles a single SMTP transaction */
  1223. smtp_transaction(mp)
  1224. struct smtp_msg *mp;
  1225. {
  1226.     char tmpstring[LINELEN];    /* where we build command lines */
  1227.  
  1228. /*    printf("SMTP_TRANSACTION() called, state=%u\n",mp->state);    */
  1229.     if (affirmative(mp)) {
  1230.         switch(mp->state) {
  1231.         case CLI_OPEN_STATE:
  1232.             mp->state = CLI_MAIL_STATE;
  1233.             /* issue MAIL command */
  1234. /*            printf("FROMADDR = %s\n",mp->fromaddr);        */
  1235.             sprintf(tmpstring,"mail from:<%s>\r\n",mp->fromaddr);
  1236.             sendit(mp,tmpstring);
  1237.             break;            
  1238.         case CLI_MAIL_STATE:
  1239.             mp->state = CLI_RCPT_STATE;
  1240.             /* issue RCPT command */
  1241.             sprintf(tmpstring,"rcpt to:<%s>\r\n",mp->toaddr);
  1242.             sendit(mp,tmpstring);
  1243.             break;
  1244.         case CLI_RCPT_STATE:
  1245.             mp->state = CLI_SEND_STATE;
  1246.             /* open text file */
  1247.             strcpy(tmpstring,mp->filename);
  1248.             strcpy(index(tmpstring,'.'),".txt");
  1249. /*            printf("text filename: %s",tmpstring);        */
  1250.             mp->tfile = fopen(tmpstring,"r");
  1251.             /* issue DATA command */
  1252.             sprintf(tmpstring,"data\r\n");
  1253.             sendit(mp,tmpstring);
  1254.             break;
  1255.         case CLI_SEND_STATE:
  1256.             /* the transmitter upcall routine will advance the
  1257.                state pointer on end of file, so we do nada... */
  1258.             break;
  1259.         case CLI_UNLK_STATE:
  1260.             unlink(mp->filename);    /* unlink workfile */
  1261.             /* close and unlink the textfile */
  1262.             fclose(mp->tfile);
  1263.             strcpy(tmpstring,mp->filename);
  1264.             strcpy(index(tmpstring,'.'),".txt");
  1265.             unlink(tmpstring);
  1266.             mp->state = CLI_QUIT_STATE;
  1267.             /* issue a quit command */
  1268.             sprintf(tmpstring,"quit\r\n");
  1269.             sendit(mp,tmpstring);
  1270.             break;
  1271.         case CLI_QUIT_STATE:
  1272.             /* either start next transaction, or quit */
  1273.             close_tcp(mp->tcb);    /* close up connection */
  1274.             break;
  1275.         }
  1276.     } else {    /* if we get here, means we got a negative reply */
  1277.             /* for the moment, just let that hose us... */
  1278.         mp->state = CLI_QUIT_STATE;
  1279.         /* issue a quit command */
  1280.         sprintf(tmpstring,"quit\r\n");
  1281.         sendit(mp,tmpstring);
  1282.     }
  1283. }
  1284.  
  1285. /* return true if the passed string contains a positive response code */
  1286. affirmative(mp)
  1287. struct smtp_msg *mp;
  1288. {
  1289.     /* 2 is always good, 3 is ok if we've just sent 'data' command */
  1290.     if ((*mp->buf = '2') || 
  1291.            ((*mp->buf = '3') && (mp->state = CLI_DATA_STATE)))
  1292.         return 1;
  1293.     else     return 0;
  1294. }
  1295.  
  1296. /* smtp receiver upcall routine.  fires up the state machine to parse input */
  1297. static
  1298. void
  1299. smtp_rec(tcb,cnt)
  1300. struct tcb *tcb;
  1301. int16 cnt;
  1302. {
  1303.     register struct smtp_msg *mp;
  1304.     char *inet_ntoa(), c;
  1305.     struct mbuf *bp;
  1306.     /* may want a void line here for procedures used */
  1307.  
  1308. /*    printf("SMTP_REC called\n");        */
  1309.     mp = (struct smtp_msg *)tcb->user;    /* point to our struct */
  1310.     recv_tcp(tcb,&bp,cnt);    /* suck up chars from low level routine */
  1311.  
  1312.     /* Assemble input line in buffer, return if incomplete */
  1313.     while(pullup(&bp,&c,1) == 1) {
  1314.         switch(c) {
  1315.         case '\r':    /* strip cr's */
  1316.             continue;
  1317.         case '\n':    /* line is finished, go do it! */
  1318.             mp->buf[mp->cnt] = '\0';
  1319.             smtp_transaction(mp);
  1320.             break;
  1321.         default:    /* other chars get added to buffer */
  1322.             mp->buf[mp->cnt++] = c;
  1323.             break;
  1324.         }
  1325.     }
  1326. }
  1327.  
  1328. /* smtp transmitter ready upcall routine.  twiddles cts flag */
  1329. static 
  1330. void
  1331. smtp_cts(tcb,cnt)
  1332. struct tcb *tcb;
  1333. int16 cnt;
  1334. {
  1335.     register struct smtp_msg *mp;
  1336.     struct mbuf *bp;
  1337.     char tmpstring[LINELEN];
  1338.     char *cp;
  1339.     int c;
  1340.  
  1341. /*    printf("SMTP_CTS called\n");        */
  1342.     mp = (struct smtp_msg *)tcb->user;    /* point to our struct */
  1343.  
  1344.     /* don't do anything until/unless we're supposed to be sending */
  1345.     if(mp->state != CLI_SEND_STATE) return;
  1346.  
  1347.     if((bp = alloc_mbuf(cnt)) == NULLBUF){
  1348.         /* Hard to know what to do here */
  1349.         return;
  1350.     }
  1351.     cp = bp->data;
  1352.     while(cnt > 1 && (c = getc(mp->tfile)) != EOF){
  1353.         *cp++ = c;
  1354.         bp->cnt++;
  1355.         cnt--;
  1356.     }
  1357.     if(bp->cnt != 0)
  1358.         send_tcp(tcb,bp);
  1359.     else
  1360.         free_p(bp);
  1361.  
  1362.     if(cnt > 1){    /* EOF seen */
  1363.         sprintf(tmpstring,"\r\n.\r\n");
  1364.         sendit(mp,tmpstring);
  1365.         mp->state = CLI_UNLK_STATE;
  1366.     }
  1367. }
  1368.  
  1369. /* smtp state change upcall routine.  cans connection on error */
  1370. static
  1371. void
  1372. smtp_state(tcb,old,new)
  1373. struct tcb *tcb;
  1374. char old,new;
  1375. {
  1376.     struct smtp_msg *mp;
  1377.  
  1378. /*    printf("SMTP_STATE called, state=%u\n",new);    */
  1379.     mp = (struct smtp_msg *)tcb->user;
  1380.     switch(new) {
  1381.     case ESTABLISHED:
  1382.         mp->state = CLI_OPEN_STATE;    /* shouldn't be needed */
  1383.         break;
  1384.     case CLOSE_WAIT:
  1385.         close_tcp(tcb);            /* shut things down */
  1386.             /* may want to do something here to shut down
  1387.                the rest of the transaction? */
  1388.         break;
  1389.     case CLOSED:
  1390.         del_tcp(tcb);            /* hosed for good */
  1391.         if(mp->filename != NULLCHAR)
  1392.             free(mp->filename);
  1393.         free((char *)mp);
  1394.         break;
  1395.     }
  1396. }
  1397.  
  1398. /* Send message back to server */
  1399. static
  1400. void
  1401. sendit(mp,message)
  1402. struct smtp_msg *mp;
  1403. char *message;
  1404. {
  1405.     struct mbuf *bp,*qdata();
  1406.  
  1407. /*    printf("SENDIT called: %s",message);        */
  1408.     bp = qdata(message,(int16)strlen(message));
  1409.     send_tcp(mp->tcb,bp);
  1410. }
  1411. SHAR_EOF
  1412. cat << \SHAR_EOF > tcpout.c
  1413. #include "machdep.h"
  1414. #include "timer.h"
  1415. #include "mbuf.h"
  1416. #include "netuser.h"
  1417. #include "internet.h"
  1418. #include "tcp.h"
  1419.  
  1420. int16 tcp_mss = DEF_MSS; /* Maximum segment size to be sent with SYN */
  1421.  
  1422. /* Send a segment on the specified connection. One gets sent only
  1423.  * if there is data to be sent or if "force" is non zero
  1424.  */
  1425. void
  1426. tcp_output(tcb)
  1427. register struct tcb *tcb;
  1428. {
  1429.     struct pseudo_header ph;
  1430.     struct mbuf *hbp;
  1431.     int16 hsize;    /* Size of header */
  1432.     struct tcp_header *tcph;
  1433.     struct mss *mssp;
  1434.     int16 ssize;    /* Size of current segment being sent,
  1435.              * including SYN and FIN flags */
  1436.     int16 dsize;    /* Size of segment less SYN and FIN */
  1437.     int16 usable;    /* Usable window */
  1438.     int16 sent;    /* Sequence count (incl SYN/FIN) already in the pipe */
  1439.  
  1440.     if(tcb == NULLTCB)
  1441.         return;
  1442.  
  1443.     switch(tcb->state){
  1444.     case LISTEN:
  1445.     case CLOSED:
  1446.         return;    /* Don't send anything */
  1447.     }
  1448.     for(;;){
  1449.         sent = tcb->snd.ptr - tcb->snd.una;
  1450.  
  1451.         /* If this is a retransmission, send only the oldest segment
  1452.          * (first-only retransmission policy)
  1453.          */
  1454.         if(tcb->retry != 0 && sent != 0)
  1455.             break;
  1456.  
  1457.         /* There can only be one outstanding segment in this state
  1458.          * since the other end would reject any segment without SYN
  1459.          */
  1460.         if(tcb->state == SYN_SENT && sent != 0)
  1461.             break;
  1462.         if(tcb->snd.wnd == 0){
  1463.             /* Allow only one closed-window probe at a time */
  1464.             if(sent != 0)
  1465.                 break;
  1466.             /* Force a closed-window probe */
  1467.             usable = 1;
  1468.         } else {
  1469.             /* usable window = offered window - unacked bytes in transit */
  1470.             usable = tcb->snd.wnd - sent;
  1471.  
  1472.             /* John Nagle's "single outstanding segment" rule.
  1473.              * Allow only one segment in the pipeline unless there is enough
  1474.              * unsent data to form at least one maximum-sized segment.
  1475.              */
  1476.             if(sent != 0 && tcb->sndcnt - sent < tcb->mss){
  1477.                 usable = 0;
  1478.             }
  1479.             /* Silly window avoidance. Don't send anything if the usable window
  1480.              * is less than a quarter of the offered window.
  1481.              * This test comes into play only when the offered window is at
  1482.              * least 4 times the MSS; otherwise Nagle's test is sufficient
  1483.              * to prevent SWS.
  1484.               */
  1485.             else if(usable < tcb->snd.wnd/4){
  1486.                 usable = 0;
  1487.             }
  1488.         }
  1489.         /* Compute size of segment to send. This is either the usable
  1490.          * window, the mss, or the amount we have on hand, whichever is less.
  1491.          * (I don't like optimistic windows)
  1492.          */
  1493.         ssize = min(tcb->sndcnt - sent,usable);
  1494.         ssize = min(ssize,tcb->mss);
  1495.         dsize = ssize;
  1496.  
  1497.         if(ssize == 0 && tcb->force == 0)
  1498.             break;        /* No need to send anything */
  1499.  
  1500.         /* Determine size of TCP header and allocate mbuf.
  1501.          * If sending SYN, allow space for the MSS option
  1502.          */
  1503.         switch(tcb->state){
  1504.         case SYN_SENT:
  1505.         case SYN_RECEIVED:
  1506.             hsize = sizeof(struct tcp_header) + sizeof(struct mss);
  1507.             break;
  1508.         default:
  1509.             hsize = sizeof(struct tcp_header);
  1510.             break;
  1511.         }
  1512.         if((hbp = alloc_mbuf(hsize)) == NULLBUF)
  1513.             break;    /* No room to form a packet */
  1514.  
  1515.         tcb->force = 0;    /* Only one forced segment! */
  1516.         hbp->cnt = hsize;
  1517.  
  1518.         tcph = (struct tcp_header *)hbp->data;
  1519.         tcph->source = htons(tcb->conn.local.port);
  1520.         tcph->dest = htons(tcb->conn.remote.port);
  1521.         tcph->offset = hsize/sizeof(int32) << DSHIFT;
  1522.         tcph->flags = 0;
  1523.  
  1524.         /* Set the SYN and ACK flags according to the state we're in. It is
  1525.          * assumed that if this segment is associated with a state transition,
  1526.          * then the state change will already have been made. This allows
  1527.          * this routine to be called from a retransmission timeout with
  1528.          * force=1.
  1529.          * If SYN is being sent, adjust the dsize counter so we'll
  1530.          * try to get the right amount of data off the send queue.
  1531.          */
  1532.         switch(tcb->state){
  1533.         case SYN_SENT:
  1534.         case SYN_RECEIVED:
  1535.             if(tcb->snd.ptr == tcb->iss){
  1536.                 tcph->flags = SYN;
  1537.                 dsize--;
  1538.             }
  1539.             /* Also send MSS */
  1540.             mssp = (struct mss *)(tcph + 1);
  1541.             mssp->kind = MSS_KIND;
  1542.             mssp->length = MSS_LENGTH;
  1543.             mssp->mss = htons(tcp_mss);
  1544.         }
  1545.         switch(tcb->state){
  1546.         case SYN_RECEIVED:
  1547.         case ESTABLISHED:
  1548.         case CLOSE_WAIT:
  1549.         case FINWAIT2:
  1550.         case TIME_WAIT:
  1551.         case CLOSING:
  1552.         case FINWAIT1:
  1553.         case LAST_ACK:
  1554.             tcph->flags |= ACK;
  1555.             break;
  1556.         }
  1557.         tcph->seq = htonl(tcb->snd.ptr);
  1558.         tcph->ack = htonl(tcb->rcv.nxt);
  1559.         tcph->wnd = htons(tcb->rcv.wnd);
  1560.         tcph->checksum = 0;
  1561.         tcph->up = 0;
  1562.  
  1563.         /* Now try to extract some data from the send queue.
  1564.          * Since SYN and FIN occupy sequence space and are reflected
  1565.          * in sndcnt but don't actually sit in the send queue,
  1566.          * dup_p will return one less than dsize if a FIN needs to be sent.
  1567.          */
  1568.         if(dsize != 0){
  1569.             if(dup_p(&hbp->next,tcb->sndq,sent,dsize) != dsize){
  1570.                 /* We ran past the end of the send queue; send a FIN */
  1571.                 tcph->flags |= FIN;
  1572.                 dsize--;
  1573.             }
  1574.         }
  1575.         /* If the entire send queue will now be in the pipe, set the
  1576.          * push flag
  1577.          */
  1578.         if(dsize != 0 && sent + ssize == tcb->sndcnt)
  1579.             tcph->flags |= PSH;
  1580.  
  1581.         tcb->snd.ptr += ssize;
  1582.         /* If this is the first transmission of a range of sequence
  1583.          * numbers, record it so we'll accept acknowledgments
  1584.          * for it later
  1585.          */
  1586.         if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
  1587.             tcb->snd.nxt = tcb->snd.ptr;
  1588.         /* Fill in fields of pseudo IP header */
  1589.         ph.source = tcb->conn.local.address;
  1590.         ph.dest = tcb->conn.remote.address;
  1591.         ph.protocol = TCP_PTCL;
  1592.         ph.zero = 0;
  1593.         ph.length = hsize + dsize;
  1594.  
  1595.         /* Compute checksum over pseudo-header, TCP header and data,
  1596.          * and pass it off to IP
  1597.          */
  1598.         tcph->checksum = cksum(&ph,hbp,ph.length);
  1599.  
  1600.         /* If we're sending some data or flags, start retransmission
  1601.          * timer if it isn't already running.
  1602.          */
  1603.         if(ssize != 0){
  1604.             if(tcb->timer.state != TIMER_RUN){
  1605.                 /* Never initialize the timer with zero; it won't run! */
  1606.                 tcb->timer.start = max(tcb->timer.start,1);
  1607.                 start_timer(&tcb->timer);
  1608.             }
  1609.             /* If round trip timer isn't running, start it */
  1610.             if(seq_ge(tcb->snd.una,tcb->rttseq))
  1611.                 tcb->rttseq = tcb->snd.ptr;
  1612.         }
  1613.         ip_send(tcb->conn.local.address,tcb->conn.remote.address,
  1614.          TCP_PTCL,tcb->tos,0,hbp,ph.length,0,0);
  1615.     }
  1616. }
  1617. SHAR_EOF
  1618. cat << \SHAR_EOF > tcpuser.c
  1619. /* User calls to TCP */
  1620. #include "machdep.h"
  1621. #include "timer.h"
  1622. #include "mbuf.h"
  1623. #include "netuser.h"
  1624. #include "internet.h"
  1625. #include "ip.h"
  1626. #include "tcp.h"
  1627.  
  1628. int16 tcp_window = DEF_WND;
  1629.  
  1630. struct tcb *
  1631. open_tcp(lsocket,fsocket,active,window,r_upcall,t_upcall,s_upcall,tos,user)
  1632. struct socket *lsocket;    /* Local socket */
  1633. struct socket *fsocket;    /* Remote socket */
  1634. int active;        /* Active/passive */
  1635. int16 window;        /* Receive window (and send buffer) sizes */
  1636. void (*r_upcall)();    /* Function to call when data arrives */
  1637. void (*t_upcall)();    /* Function to call when ok to send more data */
  1638. void (*s_upcall)();    /* Function to call when connection state changes */
  1639. char tos;
  1640. int *user;        /* User linkage area */
  1641. {
  1642.     struct connection conn;
  1643.     register struct tcb *tcb;
  1644.     void send_syn();
  1645.  
  1646.     if(lsocket == NULLSOCK){
  1647.         net_error = INVALID;
  1648.         return NULLTCB;
  1649.     }
  1650.     conn.local.address = lsocket->address;
  1651.     conn.local.port = lsocket->port;
  1652.     if(fsocket != NULLSOCK){
  1653.         conn.remote.address = fsocket->address;
  1654.         conn.remote.port = fsocket->port;
  1655.     } else {
  1656.         conn.remote.address = 0;
  1657.         conn.remote.port = 0;
  1658.     }
  1659.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  1660.         if((tcb = create_tcb(&conn)) == NULLTCB){
  1661.             net_error = NO_SPACE;
  1662.             return NULLTCB;
  1663.         }
  1664.     } else if(tcb->state != LISTEN){
  1665.         net_error = CON_EXISTS;
  1666.         return NULLTCB;
  1667.     }
  1668.     tcb->user = user;
  1669.     if(window != 0)
  1670.         tcb->window = tcb->rcv.wnd = window;
  1671.     else
  1672.         tcb->window = tcb->rcv.wnd = tcp_window;
  1673.     tcb->r_upcall = r_upcall;
  1674.     tcb->t_upcall = t_upcall;
  1675.     tcb->s_upcall = s_upcall;
  1676.     tcb->tos = tos;
  1677.     if(!active){
  1678.         setstate(tcb,LISTEN);
  1679.         return tcb;
  1680.     }
  1681.     /* Send SYN, go into SYN_SENT state */
  1682.     send_syn(tcb);
  1683.     setstate(tcb,SYN_SENT);
  1684.     tcp_output(tcb);
  1685.     tcp_stat.conout++;
  1686.     return tcb;
  1687. }
  1688. /* User send routine */
  1689. int
  1690. send_tcp(tcb,bp)
  1691. register struct tcb *tcb;
  1692. struct mbuf *bp;
  1693. {
  1694.     int16 cnt;
  1695.  
  1696.     if(tcb == NULLTCB || bp == NULLBUF){
  1697.         free_p(bp);
  1698.         net_error = INVALID;
  1699.         return -1;
  1700.     }
  1701.     cnt = len_mbuf(bp);
  1702. #ifdef    TIGHT
  1703.     /* If this would overfill our send queue, reject it entirely */
  1704.     if(tcb->sndcnt + cnt > tcb->window){
  1705.         free_p(bp);
  1706.         net_error = WOULDBLK;
  1707.         return -1;
  1708.     }
  1709. #endif
  1710.     switch(tcb->state){
  1711.     case CLOSED:
  1712.         free_p(bp);
  1713.         net_error = NO_CONN;
  1714.         return -1;
  1715.     case LISTEN:    /* Change state from passive to active */
  1716.         send_syn(tcb);
  1717.         setstate(tcb,SYN_SENT);    /* Note fall-thru */
  1718.     case SYN_SENT:
  1719.     case SYN_RECEIVED:
  1720.     case ESTABLISHED:
  1721.     case CLOSE_WAIT:
  1722.         append(&tcb->sndq,bp);
  1723.         tcb->sndcnt += cnt;
  1724.         tcp_output(tcb);
  1725.         break;
  1726.     case FINWAIT1:
  1727.     case FINWAIT2:
  1728.     case CLOSING:
  1729.     case LAST_ACK:
  1730.     case TIME_WAIT:
  1731.         free_p(bp);
  1732.         net_error = CON_CLOS;
  1733.         return -1;
  1734.     }
  1735.     return cnt;
  1736. }
  1737. /* User receive routine */
  1738. int
  1739. recv_tcp(tcb,bp,cnt)
  1740. register struct tcb *tcb;
  1741. struct mbuf **bp;
  1742. int16 cnt;
  1743. {
  1744.     if(tcb == NULLTCB || bp == (struct mbuf **)NULL){
  1745.         net_error = INVALID;
  1746.         return -1;
  1747.     }
  1748.     /* cnt == 0 means "I want it all" */
  1749.     if(cnt == 0)
  1750.         cnt = tcb->rcvcnt;
  1751.     /* If there's something on the queue, just return it regardless
  1752.      * of the state we're in.
  1753.      */
  1754.     if(tcb->rcvcnt != 0){
  1755.         /* See if the user can take all of it */
  1756.         if(tcb->rcvcnt <= cnt){
  1757.             cnt = tcb->rcvcnt;
  1758.             *bp = tcb->rcvq;
  1759.             tcb->rcvq = NULLBUF;
  1760.         } else {
  1761.             if((*bp = alloc_mbuf(cnt)) == NULLBUF){
  1762.                 net_error = NO_SPACE;
  1763.                 return -1;
  1764.             }
  1765.             pullup(&tcb->rcvq,(*bp)->data,cnt);
  1766.             (*bp)->cnt = cnt;
  1767.         }
  1768.         tcb->rcvcnt -= cnt;
  1769.         tcb->rcv.wnd += cnt;
  1770.         /* Do a window update if it was closed */
  1771.         if(cnt == tcb->rcv.wnd){
  1772.             tcb->force = 1;
  1773.             tcp_output(tcb);
  1774.         }
  1775.         return cnt;
  1776.     } else {
  1777.         /* If there's nothing on the queue, our action depends on what state
  1778.          * we're in (i.e., whether or not we're expecting any more data).
  1779.          * If no more data is expected, then simply return 0; this is
  1780.          * interpreted as "end of file".
  1781.          */
  1782.         switch(tcb->state){
  1783.         case LISTEN:
  1784.         case SYN_SENT:
  1785.         case SYN_RECEIVED:
  1786.         case ESTABLISHED:
  1787.         case FINWAIT1:
  1788.         case FINWAIT2:
  1789.             *bp = NULLBUF;
  1790.             net_error = WOULDBLK;
  1791.             return -1;
  1792.         case CLOSED:
  1793.         case CLOSE_WAIT:
  1794.         case CLOSING:
  1795.         case LAST_ACK:
  1796.         case TIME_WAIT:
  1797.             *bp = NULLBUF;
  1798.             return 0;
  1799.         }
  1800.     }
  1801.     return 0;    /* Not reached, but lint doesn't know that */
  1802. }
  1803. /* This really means "I have no more data to send". It only closes the
  1804.  * connection in one direction, and we can continue to receive data
  1805.  * indefinitely.
  1806.  */
  1807. int
  1808. close_tcp(tcb)
  1809. register struct tcb *tcb;
  1810. {
  1811.     if(tcb == NULLTCB){
  1812.         net_error = INVALID;
  1813.         return -1;
  1814.     }
  1815.     switch(tcb->state){
  1816.     case LISTEN:
  1817.     case SYN_SENT:
  1818.         close_self(tcb,NORMAL);
  1819.         return 0;
  1820.     case SYN_RECEIVED:
  1821.     case ESTABLISHED:
  1822.         tcb->sndcnt++;
  1823.         tcb->snd.nxt++;
  1824.         setstate(tcb,FINWAIT1);
  1825.         tcp_output(tcb);
  1826.         return 0;
  1827.     case CLOSE_WAIT:
  1828.         tcb->sndcnt++;
  1829.         tcb->snd.nxt++;
  1830.         setstate(tcb,LAST_ACK);
  1831.         tcp_output(tcb);
  1832.         return 0;
  1833.     case FINWAIT1:
  1834.     case FINWAIT2:
  1835.     case CLOSING:
  1836.     case LAST_ACK:
  1837.     case TIME_WAIT:
  1838.         net_error = CON_CLOS;
  1839.         return -1;
  1840.     }
  1841.     return -1;    /* "Can't happen" */
  1842. }
  1843. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  1844.  * not in the CLOSED state. This function should normally be called by the
  1845.  * user only in response to a state change upcall to CLOSED state.
  1846.  */
  1847. int
  1848. del_tcp(tcb)
  1849. register struct tcb *tcb;
  1850. {
  1851.     void unlink_tcb();
  1852.     struct reseq *rp,*rp1;
  1853.  
  1854.     if(tcb == NULLTCB){
  1855.         net_error = INVALID;
  1856.         return -1;
  1857.     }
  1858.     unlink_tcb(tcb);
  1859.     stop_timer(&tcb->timer);
  1860.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  1861.         rp1 = rp->next;
  1862.         free_p(rp->bp);
  1863.         free((char *)rp);
  1864.     }
  1865.     tcb->reseq = NULLRESEQ;
  1866.     free_p(tcb->rcvq);
  1867.     free_p(tcb->sndq);
  1868.     free((char *)tcb);
  1869.     return 0;
  1870. }
  1871. /* Do printf on a tcp connection */
  1872. /*VARARGS*/
  1873. tprintf(tcb,message,arg1,arg2)
  1874. struct tcb *tcb;
  1875. char *message,*arg1,*arg2;
  1876. {
  1877.     struct mbuf *bp;
  1878.     int16 len;
  1879.     char *cp,*index();
  1880.  
  1881.     if(tcb == NULLTCB)
  1882.         return 0;
  1883.  
  1884.     len = strlen(message) + 10;    /* fudge factor */
  1885.     if((cp = index(message,'%')) != NULLCHAR){
  1886.         /* What a gross hack! */
  1887.         len += strlen(arg1);
  1888.         if((cp = index(cp+1,'%')) != NULLCHAR){
  1889.             /* I don't believe I'm writing this */
  1890.             len += strlen(arg2);
  1891.         }
  1892.     }
  1893.     bp = alloc_mbuf(len);
  1894.     len = sprintf(bp->data,message,arg1,arg2);
  1895.     bp->cnt = strlen(bp->data);
  1896.     send_tcp(tcb,bp);
  1897.     return len;
  1898. }
  1899. SHAR_EOF
  1900. cat << \SHAR_EOF > telnet.c
  1901. #include <stdio.h>
  1902. #include "machdep.h"
  1903. #include "mbuf.h"
  1904. #include "timer.h"
  1905. #include "internet.h"
  1906. #include "icmp.h"
  1907. #include "netuser.h"
  1908. #include "tcp.h"
  1909. #include "telnet.h"
  1910. #include "session.h"
  1911.  
  1912. extern char nospace[];
  1913. int refuse_echo = 0;
  1914. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  1915.  
  1916. #ifdef    DEBUG
  1917. char *t_options[] = {
  1918.     "Transmit Binary",
  1919.     "Echo",
  1920.     "",
  1921.     "Suppress Go Ahead",
  1922.     "",
  1923.     "Status",
  1924.     "Timing Mark"
  1925. };
  1926. #endif
  1927.  
  1928. /* Execute user telnet command */
  1929. int
  1930. dotelnet(argc,argv)
  1931. int argc;
  1932. char *argv[];
  1933. {
  1934.     void t_state(),rcv_char();
  1935.     char *inet_ntoa(),*calloc();
  1936.     int32 aton();
  1937.     int send_tel();
  1938.         int unix_send_tel();
  1939.     struct session *s,*newsession();
  1940.     struct telnet *tn;
  1941.     struct tcb *tcb;
  1942.     struct socket lsocket,fsocket;
  1943.  
  1944.  
  1945.     lsocket.address = ip_addr;
  1946.     lsocket.port = lport++;
  1947.     fsocket.address = aton(argv[1]);
  1948.     if(argc < 3)
  1949.         fsocket.port = TELNET_PORT;
  1950.     else
  1951.         fsocket.port = atoi(argv[2]);
  1952.  
  1953.     /* Allocate a session descriptor */
  1954.     if((s = newsession()) == NULLSESSION){
  1955.         printf("Too many sessions\r\n");
  1956.         return 1;
  1957.     }
  1958.     s->type = TELNET;
  1959.     if ((refuse_echo == 0) && (unix_line_mode != 0)) {
  1960.         s->parse = unix_send_tel;
  1961.     } else {
  1962.         s->parse = send_tel;
  1963.     }
  1964.     current = s;
  1965.  
  1966.     /* Create and initialize a Telnet protocol descriptor */
  1967.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  1968.         printf(nospace);
  1969.         s->type = FREE;
  1970.         return 1;
  1971.     }
  1972.     tn->session = s;    /* Upward pointer */
  1973.     tn->state = TS_DATA;
  1974.     s->cb.telnet = tn;    /* Downward pointer */
  1975.  
  1976.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  1977.      rcv_char,NULLVFP,t_state,0,(int *)tn);
  1978.     if(tcb == NULLTCB || tcb->state == CLOSED){
  1979.         /* This is actually a bit dirty here. About the only time the
  1980.          * state will be closed here is if we tried to connect to
  1981.          * ourselves and got RST'ed.  If this is true then the close
  1982.          * upcall will already have freed the TCB and telnet block,
  1983.          * so we're looking at the TCB after it's back on the heap.
  1984.          */
  1985.         return 0;
  1986.     }
  1987.     tn->tcb = tcb;    /* Downward pointer */
  1988.     go();
  1989.     return 0;
  1990. }
  1991.  
  1992. /* Process typed characters */
  1993. int
  1994. unix_send_tel(buf,n)
  1995. char *buf;
  1996. int16 n;
  1997. {
  1998.     int i;
  1999.  
  2000.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  2001.         ;
  2002.     if (buf[i] == '\r') {
  2003.         buf[i] = '\n';
  2004.         n = i+1;
  2005.     }
  2006.     send_tel(buf,n);
  2007. }
  2008. int
  2009. send_tel(buf,n)
  2010. char *buf;
  2011. int16 n;
  2012. {
  2013.     struct mbuf *bp,*qdata();
  2014.     if(current == NULLSESSION || current->cb.telnet == NULLTN
  2015.      || current->cb.telnet->tcb == NULLTCB)
  2016.         return;
  2017.     bp = qdata(buf,n);
  2018.     send_tcp(current->cb.telnet->tcb,bp);
  2019. }
  2020.  
  2021. /* Process incoming TELNET characters */
  2022. int
  2023. tel_input(tn,bp)
  2024. register struct telnet *tn;
  2025. struct mbuf *bp;
  2026. {
  2027.     char c;
  2028.     int ci;
  2029.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  2030. #ifdef    FAST    /* DON'T USE -- Aztec memchr() routine is broken */
  2031.     char *memchr();
  2032.  
  2033.     /* Optimization for very common special case -- no command chars */
  2034.     if(tn->state == TS_DATA){
  2035.         while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) == NULLCHAR){
  2036.             fflush(stdout);
  2037.             write(1,bp->data,bp->cnt);
  2038.             bp = free_mbuf(bp);
  2039.         }
  2040.     }
  2041. #endif
  2042.     while(pullup(&bp,&c,1) == 1){
  2043.         ci = c & 0xff;
  2044.         switch(tn->state){
  2045.         case TS_DATA:
  2046.             if(ci == IAC){
  2047.                 tn->state = TS_IAC;
  2048.             } else {
  2049.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  2050.                     c &= 0x7f;
  2051.                 putchar(c);
  2052.             }
  2053.             break;
  2054.         case TS_IAC:
  2055.             switch(ci){
  2056.             case WILL:
  2057.                 tn->state = TS_WILL;
  2058.                 break;
  2059.             case WONT:
  2060.                 tn->state = TS_WONT;
  2061.                 break;
  2062.             case DO:
  2063.                 tn->state = TS_DO;
  2064.                 break;
  2065.             case DONT:
  2066.                 tn->state = TS_DONT;
  2067.                 break;
  2068.             case IAC:
  2069.                 putchar(c);
  2070.                 tn->state = TS_DATA;
  2071.                 break;
  2072.             default:
  2073.                 tn->state = TS_DATA;
  2074.                 break;
  2075.             }
  2076.             break;
  2077.         case TS_WILL:
  2078.             willopt(tn,ci);
  2079.             tn->state = TS_DATA;
  2080.             break;
  2081.         case TS_WONT:
  2082.             wontopt(tn,ci);
  2083.             tn->state = TS_DATA;
  2084.             break;
  2085.         case TS_DO:
  2086.             doopt(tn,ci);
  2087.             tn->state = TS_DATA;
  2088.             break;
  2089.         case TS_DONT:
  2090.             dontopt(tn,ci);
  2091.             tn->state = TS_DATA;
  2092.             break;
  2093.         }
  2094.     }
  2095. }
  2096.  
  2097. /* Telnet receiver upcall routine */
  2098. void
  2099. rcv_char(tcb,cnt)
  2100. register struct tcb *tcb;
  2101. int16 cnt;
  2102. {
  2103.     struct mbuf *bp;
  2104.     struct telnet *tn;
  2105.  
  2106.     if((tn = (struct telnet *)tcb->user) == NULLTN){
  2107.         /* Unknown connection; ignore it */
  2108.         return;
  2109.     }
  2110.     /* Hold output if we're not the current session */
  2111.     if(mode != CONV_MODE || current == NULLSESSION || current->cb.telnet != tn)
  2112.         return;
  2113.  
  2114.     if(recv_tcp(tcb,&bp,cnt) > 0)
  2115.         tel_input(tn,bp);
  2116.  
  2117.     fflush(stdout);
  2118. }
  2119.  
  2120. /* State change upcall routine */
  2121. void
  2122. t_state(tcb,old,new)
  2123. register struct tcb *tcb;
  2124. char old,new;
  2125. {
  2126.     struct telnet *tn;
  2127.     char notify = 0;
  2128.     extern char *tcpstates[];
  2129.     extern char *reasons[];
  2130.     extern char *unreach[];
  2131.     extern char *exceed[];
  2132.  
  2133.     /* Can't add a check for unknown connection here, it would loop
  2134.      * on a close upcall! We're just careful later on.
  2135.      */
  2136.     tn = (struct telnet *)tcb->user;
  2137.  
  2138.     if(current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn)
  2139.         notify = 1;
  2140.  
  2141.     switch(new){
  2142.     case CLOSE_WAIT:
  2143.         if(notify)
  2144.             printf("%s\r\n",tcpstates[new]);
  2145.         close_tcp(tcb);
  2146.         break;
  2147.     case CLOSED:    /* court adjourned */
  2148.         if(notify){
  2149.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  2150.             if(tcb->reason == NETWORK){
  2151.                 switch(tcb->type){
  2152.                 case DEST_UNREACH:
  2153.                     printf(": %s unreachable",unreach[tcb->code]);
  2154.                     break;
  2155.                 case TIME_EXCEED:
  2156.                     printf(": %s time exceeded",exceed[tcb->code]);
  2157.                     break;
  2158.                 }
  2159.             }
  2160.             printf(")\r\n");
  2161.             cmdmode();
  2162.         }
  2163.         del_tcp(tcb);
  2164.         if(tn != NULLTN)
  2165.             free_telnet(tn);
  2166.         break;
  2167.     default:
  2168.         if(notify)
  2169.             printf("%s\r\n",tcpstates[new]);
  2170.         break;
  2171.     }
  2172.     fflush(stdout);
  2173. }
  2174. /* Delete telnet structure */
  2175. static
  2176. free_telnet(tn)
  2177. struct telnet *tn;
  2178. {
  2179.     if(tn->session != NULLSESSION)
  2180.         freesession(tn->session);
  2181.  
  2182.     if(tn != NULLTN)
  2183.         free((char *)tn);
  2184. }
  2185.  
  2186. /* The guts of the actual Telnet protocol: negotiating options */
  2187. static
  2188. void
  2189. willopt(tn,opt)
  2190. struct telnet *tn;
  2191. int opt;
  2192. {
  2193.     int ack;
  2194.     void answer();
  2195.  
  2196. #ifdef    DEBUG
  2197.     printf("recv: will ");
  2198.     if(opt <= NOPTIONS)
  2199.         printf("%s\r\n",t_options[opt]);
  2200.     else
  2201.         printf("%u\r\n",opt);
  2202. #endif
  2203.     
  2204.     switch(opt){
  2205.     case TN_TRANSMIT_BINARY:
  2206.     case TN_ECHO:
  2207.     case TN_SUPPRESS_GA:
  2208.         if(tn->remote[opt] == 1)
  2209.             return;        /* Already set, ignore to prevent loop */
  2210.         if(opt == TN_ECHO){
  2211.             if(refuse_echo){
  2212.                 /* User doesn't want to accept */
  2213.                 ack = DONT;
  2214.                 break;
  2215.             } else
  2216.                 raw();        /* Put tty into raw mode */
  2217.         }
  2218.         tn->remote[opt] = 1;
  2219.         ack = DO;            
  2220.         break;
  2221.     default:
  2222.         ack = DONT;    /* We don't know what he's offering; refuse */
  2223.     }
  2224.     answer(tn,ack,opt);
  2225. }
  2226. static
  2227. void
  2228. wontopt(tn,opt)
  2229. struct telnet *tn;
  2230. int opt;
  2231. {
  2232.     void answer();
  2233.  
  2234. #ifdef    DEBUG
  2235.     printf("recv: wont ");
  2236.     if(opt <= NOPTIONS)
  2237.         printf("%s\r\n",t_options[opt]);
  2238.     else
  2239.         printf("%u\r\n",opt);
  2240. #endif
  2241.     if(opt <= NOPTIONS){
  2242.         if(tn->remote[opt] == 0)
  2243.             return;        /* Already clear, ignore to prevent loop */
  2244.         tn->remote[opt] = 0;
  2245.         if(opt == TN_ECHO)
  2246.             cooked();    /* Put tty into cooked mode */
  2247.     }
  2248.     answer(tn,DONT,opt);    /* Must always accept */
  2249. }
  2250. static
  2251. void
  2252. doopt(tn,opt)
  2253. struct telnet *tn;
  2254. int opt;
  2255. {
  2256.     void answer();
  2257.     int ack;
  2258.  
  2259. #ifdef    DEBUG
  2260.     printf("recv: do ");
  2261.     if(opt <= NOPTIONS)
  2262.         printf("%s\r\n",t_options[opt]);
  2263.     else
  2264.         printf("%u\r\n",opt);
  2265. #endif
  2266.     switch(opt){
  2267. #ifdef    FUTURE    /* Use when local options are implemented */
  2268.         if(tn->local[opt] == 1)
  2269.             return;        /* Already set, ignore to prevent loop */
  2270.         tn->local[opt] = 1;
  2271.         ack = WILL;
  2272.         break;
  2273. #endif
  2274.     default:
  2275.         ack = WONT;    /* Don't know what it is */
  2276.     }
  2277.     answer(tn,ack,opt);
  2278. }
  2279. static
  2280. void
  2281. dontopt(tn,opt)
  2282. struct telnet *tn;
  2283. int opt;
  2284. {
  2285.     void answer();
  2286.  
  2287. #ifdef    DEBUG
  2288.     printf("recv: dont ");
  2289.     if(opt <= NOPTIONS)
  2290.         printf("%s\r\n",t_options[opt]);
  2291.     else
  2292.         printf("%u\r\n",opt);
  2293. #endif
  2294.     if(opt <= NOPTIONS){
  2295.         if(tn->local[opt] == 0){
  2296.             /* Already clear, ignore to prevent loop */
  2297.             return;
  2298.         }
  2299.         tn->local[opt] = 0;
  2300.     }
  2301.     answer(tn,WONT,opt);
  2302. }
  2303. static
  2304. void
  2305. answer(tn,r1,r2)
  2306. struct telnet *tn;
  2307. int r1,r2;
  2308. {
  2309.     struct mbuf *bp,*qdata();
  2310.     char s[3];
  2311.  
  2312. #ifdef    DEBUG
  2313.     switch(r1){
  2314.     case WILL:
  2315.         printf("sent: will ");
  2316.         break;
  2317.     case WONT:
  2318.         printf("sent: wont ");
  2319.         break;
  2320.     case DO:
  2321.         printf("sent: do ");
  2322.         break;
  2323.     case DONT:
  2324.         printf("sent: dont ");
  2325.         break;
  2326.     }
  2327.     if(r2 <= 6)
  2328.         printf("%s\r\n",t_options[r2]);
  2329.     else
  2330.         printf("%u\r\n",r2);
  2331. #endif
  2332.  
  2333.     s[0] = IAC;
  2334.     s[1] = r1;
  2335.     s[2] = r2;
  2336.     bp = qdata(s,(int16)3);
  2337.     send_tcp(tn->tcb,bp);
  2338. }
  2339. SHAR_EOF
  2340. #    End of shell archive
  2341. exit 0
  2342. -- 
  2343. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  2344. Have five nice days.
  2345.